#include "Microfono.h"

using std::cout;
using std::cerr;
using std::endl;

Microfono::Microfono() :DispositivoAudio() {
	int ret;
	unsigned int val;
	Codificador = new Cod_Audio();
	Codificador->register_codecs();
	// Abro el dispositivo
	ret = snd_pcm_open(&this->handle, "default", SND_PCM_STREAM_CAPTURE, 0);
	if (ret < 0) {
		cerr << "no se pudo abrir el dispositivo: " << snd_strerror(ret)
				<< endl;
		exit(1);
	}
	// Pido memoria para los parametros
	snd_pcm_hw_params_alloca(&this->params);
	// Valores por defecto
	snd_pcm_hw_params_any(this->handle, this->params);
	// modo interleaved
	snd_pcm_hw_params_set_access(this->handle, this->params,
			SND_PCM_ACCESS_RW_INTERLEAVED);
	// Formato signed 16-bit little-endian
	snd_pcm_hw_params_set_format(this->handle, this->params,
			SND_PCM_FORMAT_S16_LE);
	// Seteo cantidad de canales
	snd_pcm_hw_params_set_channels(this->handle, this->params, this->canales);
	val = 44100; // bits/segundo sampling rate (calidad CD)
	snd_pcm_hw_params_set_rate_near(this->handle, this->params, &val,
			&this->dir);
	snd_pcm_hw_params_set_period_size_near(this->handle, this->params,
			&this->frames, &this->dir);
	// Cargo los parametros al driver
	ret = snd_pcm_hw_params(this->handle, this->params);
	if (ret < 0) {
		cerr << "no se pudieron setear los parametros: " << snd_strerror(ret)
				<< endl;
		exit(1);
	}
	// Tamanio del periodo
	snd_pcm_hw_params_get_period_size(this->params, &this->frames, &this->dir);

	Codificador->busca_encoder();

	Codificador->ini_contexto();

	Codificador->abre_encoder();
}

void Microfono::set_socket(Socket* socket) {
	this->socket = socket;
}

int Microfono::ejecutar() {
	static int ret, out_size, frame_Codificado_size, frame_byte_size;
	static signed short* aux; // Puntero auxiliar
	static int faltan; // Frames que faltan para completar un periodo
	static uint8_t *frame_Codificado = NULL;
	frame_byte_size = Codificador->getFrameSize();
	frame_Codificado_size = 2500;
	frame_Codificado = (uint8_t*) malloc(frame_Codificado_size);
	buf = new short[frame_byte_size * 2];
	aux = buf;
	faltan = frame_byte_size;
	while (faltan > 0) {
		ret = snd_pcm_readi(handle, aux, faltan);
		if (ret < 0) {
			if (this->recuperacion(ret) < 0) {
				cerr << "microphone: Write error: " << snd_strerror(ret)
						<< endl;
				exit(EXIT_FAILURE);
			}
			break; // Descarto el periodo
		}
		if (ret == -EPIPE) {
			// EPIPE = overrun
			cerr << "overrun occurred" << endl;
			snd_pcm_prepare(this->handle);
		}
		aux += ret * canales;
		faltan -= ret;
	}
	out_size = Codificador->codificar(buf, &frame_Codificado_size,
			&frame_Codificado);
	if (out_size < 0) {
		return -1;
	}

	char cod_op = 'A';
	if(!(socket->enviar((const char*) &cod_op, 1))) {
		cerr << "Error audio" << endl;
		return -1;
	}
	if(!(socket->enviar((const char*) &out_size, 4))) {
		cerr << "Error audio" << endl;
		return -1;
	}
	if(!(socket->enviar((const char*) frame_Codificado, out_size))) {
		cerr << "Error audio" << endl;
		return -1;
	}

	av_free(frame_Codificado);
	//snd_mixer_close(mixer);
	delete[] buf;
	return 0;
}

Microfono::~Microfono() {
	snd_pcm_drain(this->handle);
	snd_pcm_close(this->handle);
	delete Codificador;
}

